#ifndef JEGEO_BOOSTADAPTOR_H
#define JEGEO_BOOSTADAPTOR_H
#include <QDebug>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/box.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/geometries/register/segment.hpp>
#include <boost/geometry/index/rtree.hpp>
#include "jegeo/common.hpp"

namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;

namespace jegeo {

namespace bmodel {
template<typename T>
using BPoint = bg::model::point<T, 2, bg::cs::cartesian>;

template<typename T>
using BBox = bg::model::box<BPoint<T>>;

template<typename T>
using BSegment = bg::model::segment<BPoint<T>>;

template<typename T>
using BBoxRTree = bgi::rtree<std::pair<BBox<T>, size_t>, bgi::quadratic<16>>;

template<typename T>
using BSegmentRTree = bgi::rtree<std::pair<BSegment<T>, size_t>, bgi::quadratic<16>>;

template<typename T>
using BBoxResults = std::vector<std::pair<BBox<T>, int>>;

template<typename T>
using BSegmentResults = std::vector<std::pair<BSegment<T>, int>>;
} // namespace bmodel

namespace point {
template<typename T>
bmodel::BPoint<T> to_bpoint(const Point<T> &jepoint)
{
    return bmodel::BPoint<T>{std::get<0>(jepoint), std::get<1>(jepoint)};
}
} // namespace point

namespace rect {
template<typename T>
bmodel::BBox<T> to_bbox(const Rect<T> &jebox)
{
    return bmodel::BBox<T>{point::to_bpoint(get_p1(jebox)), point::to_bpoint(get_p2(jebox))};
}
} // namespace rect

namespace segment {
template<typename T>
bmodel::BSegment<T> to_bsegment(const Segment<T> &seg)
{
    return bmodel::BSegment<T>{point::to_bpoint(get_ps(seg)), point::to_bpoint(get_pe(seg))};
}

template<typename T>
bmodel::BSegment<T> to_bsegment(const Point<T> &p1, const Point<T> &p2)
{
    return bmodel::BSegment<T>{point::to_bpoint(p1), point::to_bpoint(p2)};
}
} // namespace segment

namespace edge {
template<typename T>
bmodel::BSegment<T> to_bsegment(const Edge<T> &edge)
{
    return bmodel::BSegment<T>{point::to_bpoint(get_ps(edge)), point::to_bpoint(get_pe(edge))};
}
} // namespace edge

namespace rtree {
template<typename T>
bmodel::BBoxRTree<T> create_box_rtree(const std::vector<Edge<T>> &edges)
{
    std::vector<std::pair<bmodel::BBox<T>, size_t>> rtvalues;
    for (size_t i = 0; i < edges.size(); i++) {
        auto seg = edges[i];
        rtvalues.push_back(std::make_pair(rect::to_bbox(edge::get_bound_rect(seg)), i));
    }
    return bmodel::BBoxRTree<T>(rtvalues.begin(), rtvalues.end());
}

template<typename T>
bmodel::BBoxRTree<T> create_box_rtree(const std::vector<Polygon<T>> &polygons) {
    std::vector<std::pair<bmodel::BBox<T>, size_t>> rtvalues;
    for (size_t i = 0; i < polygons.size(); i++) {
        const auto &poly = polygons[i];
        rtvalues.push_back(std::make_pair(rect::to_bbox(polygon::get_bound_rect(poly)), i));
    }
    return bmodel::BBoxRTree<T>(rtvalues.begin(), rtvalues.end());;
}

template<typename T>
bmodel::BSegmentRTree<T> create_segment_rtree(const std::vector<Edge<T>> &edges)
{
    std::vector<std::pair<bmodel::BSegment<T>, size_t>> rtvalues;
    for (size_t i = 0; i < edges.size(); i++) {
        auto seg = edges[i];
        rtvalues.push_back(std::make_pair(edge::to_bsegment(seg), i));
    }
    return bmodel::BSegmentRTree<T>(rtvalues.begin(), rtvalues.end());
}

} // namespace rtree
} // namespace jegeo

#endif // JEGEO_BOOSTADAPTOR_H
